#include "Layer.h"
#include "Camera.h"
#include "Tile.h"
#include "BaseObject.h"
#include "BaseCharacter.h"
#include "../wrappers/CSGD_TextureManager.h"
#include "../wrappers/CSGD_EventSystem.h"
#include "../wrappers/CSGD_MessageSystem.h"


#include <cassert>


CLayer::CLayer(void)
{
	m_nPaletID		= -1;
	m_unTileHeight	= 0;
	m_unTileWidth	= 0;
	m_unMapHeight	= 0;
	m_unMapWidth	= 0;
	m_unPaletWidth	= 0;
	m_unPaletHeight = 0;
	m_fPaletScale	= 0;
	m_fScrollRate	= 0;
	m_pTM			= CSGD_TextureManager::GetInstance();

	m_bWrap			= false;
	m_bTopLayer		= true;
}


CLayer::~CLayer(void)
{
	vector< CTile* >::iterator tileIter = m_Tiles.begin();
	for( ; tileIter != m_Tiles.end(); ++tileIter )
	{
		delete (*tileIter);
		m_Tiles.erase( tileIter-- );
	}
}

void CLayer::RenderLayer( void )
{
	vector< CTile* >::iterator tileIter = m_Tiles. begin();
	for( unsigned int unCurrTile = 0; tileIter != m_Tiles.end(); ++tileIter, ++unCurrTile )
	{
		// World Position
		unsigned int unMapColumn = (m_Tiles.size() % unCurrTile)*m_unTileWidth;

		// On Camera?
		if( m_pCamera->OnCamera( (float)((*tileIter)->m_rRect.right) ) && 
			m_pCamera->OnCamera( (float)(*tileIter)->m_rRect.left ) )
		{

			int nColumn = (signed)m_unPaletWidth % (*tileIter)->GetTileID();
			int nRow    = (signed)m_unPaletHeight/ (*tileIter)->GetTileID();

			RECT rSource;
			rSource.top		= (LONG)(m_fPaletScale * (float)(nRow * m_unTileHeight));
			rSource.bottom  = (LONG)((float)m_unTileHeight * m_fPaletScale) + rSource.top;
			rSource.left    = (LONG)((float)(nColumn * m_unTileWidth) * m_fPaletScale);
			rSource.bottom  = (LONG)((float)m_unTileHeight * m_fPaletScale) + rSource.left;

			// Render Tile
			m_pTM->Draw( m_nPaletID,
				GetTileRelativeXPosition((*tileIter)),
				GetTileRelativeYPosition((*tileIter)),
				1.0/m_fPaletScale, 1.0/m_fPaletScale,
				&rSource );

		}
		
	}
}


void CLayer::UpdateLayer( float dCameraPosition )
{
	m_nScrollPosition += (int)(dCameraPosition*m_fScrollRate);
}


bool CLayer::AddTile( CTile* pTile )
{
	if( m_unMapWidth % m_Tiles.size() > 0 )
	{
		pTile->m_rRect.left = m_Tiles.back()->m_rRect.right;
		pTile->m_rRect.right = pTile->m_rRect.left + (LONG)m_unTileWidth;
	}
	else
	{
		pTile->m_rRect.left = 0;
		pTile->m_rRect.right= (LONG)m_unTileWidth;
	}
	pTile->m_rRect.top = (LONG)((m_unMapHeight / m_Tiles.size()) * m_unTileHeight);

	m_Tiles.push_back( pTile );
	return true;
}

bool CLayer::CheckCharacterCollision( CBaseObject* pOther )
{
	vector< CTile* > vTiles = GetSurroundingTiles( pOther );
	vector< CTile* >::iterator tileIter = vTiles.begin();
	RECT rOverlap;
	for( ; tileIter != vTiles.end(); ++tileIter )
	{
		if( IntersectRect( &rOverlap, &pOther->GetBaseRect(), &(*tileIter)->m_rRect ) )
		{
			switch( (*tileIter)->GetTriggerType() )
			{
			case NO_TRIGGER:
				{
			
				}
				break;
			case TRIGGER_DAMAGE_AND_COLLISION:
			case TRIGGER_COLLISION:
				{
					CBaseCharacter* pCharacter = dynamic_cast< CBaseCharacter* >( pOther );
					if( pCharacter != nullptr )
					{
						if( rOverlap.right == pOther->GetBaseRect().right )
							pOther->SetRelativeXPosition( (float)rOverlap.left - (float)pOther->GetWidth()/2.0f );
						else if( rOverlap.left == pOther->GetBaseRect().left )
							pOther->SetRelativeXPosition( (float)rOverlap.right + (float)pOther->GetWidth()/2.0f );
						else if( rOverlap.top == pOther->GetBaseRect().top )
							pOther->SetRelativeZPosition( pOther->GetRelativePosition().fZ + (float)(rOverlap.bottom - rOverlap.top) );
						else if( rOverlap.bottom == pOther->GetBaseRect().bottom )
							pOther->SetRelativeZPosition( pOther->GetRelativePosition().fZ - (float)(rOverlap.bottom - rOverlap.top) );

					}
				}
				if( (*tileIter)->GetTriggerType() != TRIGGER_DAMAGE_AND_COLLISION )
					break;
			case TRIGGER_DAMAGE:
				{
					// send message CDealDamage( 10, pOther );
				}
				break;
			case TRIGGER_EVENT:
				{
					CSGD_EventSystem::GetInstance()->SendEvent( (*tileIter)->GetTrigger(), pOther );
				}
				break;
			default:
				break;
			}
			return true;
		}
		

	}

	return false;
}


vector< CTile* > CLayer::GetSurroundingTiles( CBaseObject* pCharacter )
{
	vector< CTile* > vTiles;
	unsigned int unCharacterPos = (unsigned int)pCharacter->GetPosition().fX;
	unsigned int unIndex = unCharacterPos/m_unMapWidth;
	for( unsigned int i = 0; i < m_unMapHeight; i++, unIndex += m_unMapWidth )
	{
		vTiles.push_back( m_Tiles[unIndex - 4] );
		vTiles.push_back( m_Tiles[unIndex - 3] );
		vTiles.push_back( m_Tiles[unIndex - 2] );
		vTiles.push_back( m_Tiles[unIndex - 1] );
		vTiles.push_back( m_Tiles[unIndex] );
		vTiles.push_back( m_Tiles[unIndex + 1] );
		vTiles.push_back( m_Tiles[unIndex + 2] );
		vTiles.push_back( m_Tiles[unIndex + 3] );
		vTiles.push_back( m_Tiles[unIndex + 4] );
	}
	return vTiles;
}


int CLayer::GetTileRelativeXPosition( CTile* pTile )
{
	return (int)(pTile->m_rRect.right - (LONG)m_pCamera->GetWorldPosition());
}


int CLayer::GetTileRelativeYPosition( CTile* pTile )
{
	return (int)(pTile->m_rRect.top);
}
